package iface.aplicativo.negocio.aps;

import iface.aplicativo.integracao.dao.CategoriaDAO;
import iface.aplicativo.integracao.dao.ContaDAO;
import iface.aplicativo.integracao.dao.FeriadoDAO;
import iface.aplicativo.integracao.dao.FormaPagamentoDAO;
import iface.aplicativo.integracao.dao.LancamentoDAO;
import iface.aplicativo.integracao.dao.LancamentoItemDAO;
import iface.aplicativo.integracao.dao.PessoaDAO;
import iface.aplicativo.integracao.dao.VeiculoDAO;
import iface.aplicativo.negocio.entidade.Conta;
import iface.aplicativo.negocio.entidade.Lancamento;
import iface.aplicativo.negocio.entidade.LancamentoItem;
import iface.aplicativo.negocio.entidade.Pessoa;
import iface.aplicativo.negocio.entidade.Veiculo;
import iface.aplicativo.negocio.enumerador.PeriodicidadeEnum;
import iface.aplicativo.negocio.enumerador.TipoLancamentoEnum;
import iface.aplicativo.negocio.enumerador.TipoVinculoLancamentoEnum;
import iface.aplicativo.to.ContasTO;
import iface.aplicativo.to.SituacaoContasTO;
import iface.aplicativo.util.Constantes;
import iface.aplicativo.util.FeriadoUtil;
import iface.aplicativo.util.ResourceMessageFactory;
import iface.aplicativo.util.UtilResource;
import iface.arquitetura.utilitario.ListaTO;
import iface.arquitetura.utilitario.ListaUtil;
import iface.arquitetura.utilitario.ResourceMessageAnnotation;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;
import javax.faces.model.SelectItem;

import org.apache.commons.beanutils.PropertyUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(readOnly = true, rollbackFor = { Exception.class })
public class ManterReceitasAPS {

	@ResourceMessageAnnotation(propertiesFile = { Constantes.RECURSO_MENSAGENS })
	private UtilResource resource = ResourceMessageFactory.inicialize(this);

	@Resource
	LancamentoDAO lancamentoDAO;
	@Resource
	LancamentoItemDAO lancamentoItemDAO;
	@Resource
	CategoriaDAO categoriaDAO;
	@Resource
	ContaDAO contaDAO;
	@Resource
	FormaPagamentoDAO formaPagamentoDAO;
	@Resource
	PessoaDAO pessoaDAO;
	@Resource
	VeiculoDAO veiculoDAO;
	@Resource
	FeriadoDAO feriadoDAO;

	@Transactional(propagation = Propagation.REQUIRED)
	public String cadastrarLancamento(Lancamento entidade, int repetir,
			PeriodicidadeEnum periodicidade) throws Exception {
		this.validarCamposLancamento(entidade);

		FeriadoUtil feriadoUtil = new FeriadoUtil(feriadoDAO);
		Date dataVencimento = entidade.getDtVencimento();

		if (entidade.isDiaUtil()) {
			Date dataDiaUtil = feriadoUtil.getDiaPosterior(
					entidade.getDtVencimento(), FeriadoUtil.DIA_UTIL);
			entidade.setDtVencimento(dataDiaUtil);
		}

		List<LancamentoItem> itens = entidade.getLancamentoItems();

		if (entidade.getIdLancamento() == null) {
			Lancamento entidadeTemp = new Lancamento();
			PropertyUtils.copyProperties(entidadeTemp, entidade);

			entidadeTemp.setLancamentoItems(null);
			this.lancamentoDAO.inserir(entidadeTemp);
			this.salvarItens(entidadeTemp, itens);

			if (repetir > 0) {
				for (int i = 0; i < repetir; i++) {
					entidadeTemp = new Lancamento();
					PropertyUtils.copyProperties(entidadeTemp, entidade);

					Calendar calendario = Calendar.getInstance();
					calendario.setTime(dataVencimento);

					if (periodicidade.equals(PeriodicidadeEnum.D)) {
						calendario.roll(Calendar.DAY_OF_MONTH, 1);
					} else if (periodicidade.equals(PeriodicidadeEnum.M)) {
						calendario.roll(Calendar.MONTH, 1);
					} else if (periodicidade.equals(PeriodicidadeEnum.A)) {
						calendario.roll(Calendar.YEAR, 1);
					}

					dataVencimento = calendario.getTime();

					if (entidadeTemp.isDiaUtil()) {
						Date dataDiaUtil = feriadoUtil.getDiaPosterior(
								dataVencimento, FeriadoUtil.DIA_UTIL);
						entidadeTemp.setDtVencimento(dataDiaUtil);
					}

					entidadeTemp.setLancamentoItems(null);
					this.lancamentoDAO.inserir(entidadeTemp);
					this.salvarItens(entidadeTemp, itens);
				}
			}
			return this.resource.getMensagens("MSG01");
		} else {
			this.lancamentoDAO.alterar(entidade);
			this.salvarItens(entidade, itens);
			return this.resource.getMensagens("MSG02");
		}

	}

	public void salvarItens(Lancamento entidade,
			List<LancamentoItem> itensLancamento) throws Exception {
		Collection<LancamentoItem> itens = this.lancamentoItemDAO
				.consultarItensPorLancamentoId(entidade.getIdLancamento());

		if (itens != null && !itens.isEmpty()) {
			for (LancamentoItem lancamentoItem : itens) {
				if (!itensLancamento.contains(lancamentoItem)) {
					this.lancamentoItemDAO.remover(lancamentoItem);
				}
			}
			this.lancamentoItemDAO.getHibernateTemplate().clear();
			for (LancamentoItem lancamentoItem : itensLancamento) {
				LancamentoItem lancamentoItemTemp = new LancamentoItem();
				PropertyUtils
						.copyProperties(lancamentoItemTemp, lancamentoItem);
				lancamentoItemTemp.setLancamento(entidade);
				this.lancamentoItemDAO.salvar(lancamentoItem);
			}
		} else if (itensLancamento != null && !itensLancamento.isEmpty()) {
			for (LancamentoItem lancamentoItem : itensLancamento) {
				LancamentoItem lancamentoItemTemp = new LancamentoItem();
				PropertyUtils
						.copyProperties(lancamentoItemTemp, lancamentoItem);
				lancamentoItemTemp.setLancamento(entidade);
				this.lancamentoItemDAO.inserir(lancamentoItemTemp);
			}
		}

	}

	public void validarCamposLancamento(Lancamento entidade) throws Exception {
		if (entidade != null) {
			if (entidade.getCategoria() != null
					&& entidade.getCategoria().getId() == null) {
				entidade.setCategoria(null);
			}
			if (entidade.getConta() != null
					&& entidade.getConta().getId() == null) {
				entidade.setConta(null);
			}
			if (entidade.getFormaPagamento() != null
					&& entidade.getFormaPagamento().getId() == null) {
				entidade.setFormaPagamento(null);
			}
			if (entidade.getPessoa() != null
					&& entidade.getPessoa().getIdPessoa() == null) {
				entidade.setPessoa(null);
			}
			if (entidade.getVeiculo() != null
					&& entidade.getVeiculo().getIdVeiculo() == null) {
				entidade.setVeiculo(null);
			}
		}
	}

	@Transactional(propagation = Propagation.REQUIRED)
	public String baixarLancamento(Lancamento entidade) throws Exception {
		try {
			validarCamposLancamento(entidade);
			entidade.setDtBaixa(new Date());
			entidade.setLancamentoItems(null);
			this.lancamentoDAO.alterar(entidade);
		} catch (Exception ex) {
			throw new Exception(ex);
		}
		return this.resource.getMensagens("MSG021");
	}

	public ContasTO atualizarContasPagar(Date dataContas) throws Exception {
		ContasTO contasTO = new ContasTO();
		try {
			Double vencidas = 0.0;
			Double vencer = 0.0;
			Double totalPago = 0.0;
			Double totalGeral = 0.0;

			List<Lancamento> vencidasLista = this.lancamentoDAO
					.consultarLancamentosVencidasPorData(dataContas,
							TipoLancamentoEnum.P);
			for (Lancamento lancamento : vencidasLista) {
				vencidas += lancamento.getValorTotal();
			}

			List<Lancamento> aVencerLista = this.lancamentoDAO
					.consultarLancamentosAVencerPorData(dataContas,
							TipoLancamentoEnum.P);
			for (Lancamento lancamento : aVencerLista) {
				vencer += lancamento.getValorTotal();
			}

			List<Lancamento> pagosLista = this.lancamentoDAO
					.consultarLancamentosPagosPorData(dataContas,
							TipoLancamentoEnum.P);
			for (Lancamento lancamento : pagosLista) {
				totalPago += lancamento.getValorTotal();
			}

			totalGeral = vencidas + vencer + totalPago;

			contasTO.setVencidas(vencidas);
			contasTO.setPagar(vencer);
			contasTO.setTotalPago(totalPago);
			contasTO.setTotalGeral(totalGeral);

		} catch (Exception ex) {
			throw new Exception(ex);
		}
		return contasTO;
	}

	public ContasTO atualizarContasReceber(Date dataContas) throws Exception {
		ContasTO contasTO = new ContasTO();
		try {
			Double vencidas = 0.0;
			Double receber = 0.0;
			Double totalRecebido = 0.0;
			Double totalGeral = 0.0;

			List<Lancamento> vencidasLista = this.lancamentoDAO
					.consultarLancamentosVencidasPorData(dataContas,
							TipoLancamentoEnum.R);
			for (Lancamento lancamento : vencidasLista) {
				vencidas += lancamento.getValorTotal();
			}

			List<Lancamento> aVencerLista = this.lancamentoDAO
					.consultarLancamentosAVencerPorData(dataContas,
							TipoLancamentoEnum.R);
			for (Lancamento lancamento : aVencerLista) {
				receber += lancamento.getValorTotal();
			}

			List<Lancamento> pagosLista = this.lancamentoDAO
					.consultarLancamentosPagosPorData(dataContas,
							TipoLancamentoEnum.R);
			for (Lancamento lancamento : pagosLista) {
				totalRecebido += lancamento.getValorTotal();
			}

			totalGeral = vencidas + receber + totalRecebido;

			contasTO.setVencidas(vencidas);
			contasTO.setReceber(receber);
			contasTO.setTotalRecebido(totalRecebido);
			contasTO.setTotalGeral(totalGeral);

		} catch (Exception ex) {
			throw new Exception(ex);
		}
		return contasTO;
	}

	@Transactional(propagation = Propagation.REQUIRED)
	public String excluirLancamentoItem(LancamentoItem entidade)
			throws Exception {
		try {
			this.lancamentoItemDAO.remover(entidade);
		} catch (Exception ex) {
			throw new Exception(ex);
		}
		return this.resource.getMensagens("MSG03");
	}

	public Collection<Lancamento> consultarTodosLancamentos() {
		Collection<Lancamento> lancamentos = this.lancamentoDAO.consultar();
		for (Lancamento lancamento : lancamentos) {
			lancamento.getLancamentoItems().size();
		}
		return lancamentos;
	}

	public Collection<Lancamento> consultarLancamentosPorFiltro(
			Date dataVencimentoInicial, Date dataVencimentoFinal,
			SituacaoContasTO situacaoContasTO) {
		Collection<Lancamento> lancamentos = this.lancamentoDAO
				.consultarLancamentosPorFiltro(dataVencimentoInicial,
						dataVencimentoFinal, situacaoContasTO);
		for (Lancamento lancamento : lancamentos) {
			lancamento.getLancamentoItems().size();
		}

		return lancamentos;
	}

	public Collection<ListaTO> consultarTodasCategorias() {
		final List<ListaTO> lista = ListaUtil.listaBean2Lista(
				this.categoriaDAO.consultar(), "id", "nmCategoria");

		return lista;
	}

	public Collection<Conta> getObterContasAtualizadas() {
		Collection<Conta> contas = this.contaDAO.consultar();
		for (Conta conta : contas) {
			conta.getSaldo();
		}

		return contas;
	}

	public Collection<ListaTO> consultarTodasContas() {
		Collection<Conta> contas = this.contaDAO.consultar();
		ArrayList<ListaTO> res = null;
		try {
			res = new ArrayList<ListaTO>();
			ListaTO listaTOaux = new ListaTO("", ":: Selecione ::");
			res.add(listaTOaux);
			for (final Conta c : contas) {
				ListaTO to = new ListaTO();
				to.setValue(c.getId().toString());
				to.setLabel(c.getNmBanco() + " :: " + c.getNrAgencia() + " :: "
						+ c.getNrConta());
				res.add(to);
			}
		} catch (final Exception e) {
		}

		return res;
	}

	public Collection<ListaTO> consultarTodasFormasPagamento() {
		final List<ListaTO> lista = ListaUtil.listaBean2Lista(
				this.formaPagamentoDAO.consultar(), "id", "descricao");

		return lista;
	}

	public List<SelectItem> consultarTiposLancamento() {
		List<SelectItem> lista = new ArrayList<SelectItem>();
		lista.add(new SelectItem(TipoLancamentoEnum.P, TipoLancamentoEnum.P
				.getLabel()));
		lista.add(new SelectItem(TipoLancamentoEnum.R, TipoLancamentoEnum.R
				.getLabel()));

		return lista;
	}

	public List<SelectItem> consultarTiposVinculos() {
		List<SelectItem> lista = new ArrayList<SelectItem>();
		lista.add(new SelectItem(TipoVinculoLancamentoEnum.V,
				TipoVinculoLancamentoEnum.V.getLabel()));
		lista.add(new SelectItem(TipoVinculoLancamentoEnum.C,
				TipoVinculoLancamentoEnum.C.getLabel()));
		lista.add(new SelectItem(TipoVinculoLancamentoEnum.O,
				TipoVinculoLancamentoEnum.O.getLabel()));

		return lista;
	}

	public List<SelectItem> consultarPeriodos() {
		List<SelectItem> lista = new ArrayList<SelectItem>();
		lista.add(new SelectItem(PeriodicidadeEnum.D, PeriodicidadeEnum.D
				.getLabel()));
		lista.add(new SelectItem(PeriodicidadeEnum.M, PeriodicidadeEnum.M
				.getLabel()));
		lista.add(new SelectItem(PeriodicidadeEnum.A, PeriodicidadeEnum.A
				.getLabel()));

		return lista;
	}

	public Collection<Pessoa> consultarPessoasPorNome(final String nome) {
		return this.pessoaDAO.consultarFornecedoresPorNome(nome);
	}

	public Collection<Veiculo> consultarVeiculosPorPlaca(final String nrPlaca) {
		return this.veiculoDAO.consultarVeiculosPorPlaca(nrPlaca);
	}

}
